/**
 * Captures session IDs and campaign information from third party analytic vendors
 * installed on the same page.
 *
 * Third party analytics vendors currently supported:
 *
 * * Google Analytics
 * * Adobe Analytics (formerly Omniture Sitecatalyst)
 * * IBM Digital Analytics (formerly Coremetrics)
 *
 * ## Beacon Parameters
 *
 * This plugin adds the following parameters to the beacon:
 *
 * * `tp.ga.clientid`: Google Analytics [clientID](https://developers.google.com/analytics/devguides/collection/analyticsjs/cookies-user-id) (unique id per visitor)
 * * `tp.ga.utm_source`: Google Analytics [Campaign source](https://support.google.com/analytics/answer/1033863?hl=en)
 * * `tp.ga.utm_medium`: Google Analytics [Campaign medium](https://support.google.com/analytics/answer/1033863?hl=en)
 * * `tp.ga.utm_term`: Google Analytics [Campaign term](https://support.google.com/analytics/answer/1033863?hl=en)
 * * `tp.ga.utm_content`: Google Analytics [Campaign content](https://support.google.com/analytics/answer/1033863?hl=en)
 * * `tp.ga.utm_campaign`: Google Analytics [Campaign ID](https://support.google.com/analytics/answer/1033863?hl=en)
 * * `tp.aa.aid`: Adobe Analytics [Analytics ID (AID)](https://marketing.adobe.com/resources/help/en_US/reference/)
 * * `tp.aa.mid`: Adobe Analytics [Marketing ID (MID)](https://marketing.adobe.com/resources/help/en_US/reference/)
 * * `tp.aa.campaign`: Adobe Analytics [Campaign ID](https://marketing.adobe.com/resources/help/en_US/reference/)
 * * `tp.aa.purchaseid`: Adobe Analytics [Purchase ID](https://marketing.adobe.com/resources/help/en_US/reference/)
 * * `tp.ia.coreid`: IBM Analytics [Core ID (unique id per visitor)](https://www.ibm.com/support/knowledgecenter/en/SSPG9M/Analytics/kc_welcome_analytics.html)
 * * `tp.ia.mmc_vendor`: IBM Analytics [Campaign vendor](https://www.ibm.com/support/knowledgecenter/en/SSPG9M/Analytics/kc_welcome_analytics.html)
 * * `tp.ia.mmc_category`: IBM Analytics [Campaign category](https://www.ibm.com/support/knowledgecenter/en/SSPG9M/Analytics/kc_welcome_analytics.html)
 * * `tp.ia.mmc_placement`: IBM Analytics [Campaign placement](https://www.ibm.com/support/knowledgecenter/en/SSPG9M/Analytics/kc_welcome_analytics.html)
 * * `tp.ia.mmc_item`: IBM Analytics [Campaign item](https://www.ibm.com/support/knowledgecenter/en/SSPG9M/Analytics/kc_welcome_analytics.html)
 * * `tp.ia.sp_type`: IBM Analytics [Site promotion type](https://www.ibm.com/support/knowledgecenter/en/SSPG9M/Analytics/kc_welcome_analytics.html)
 * * `tp.ia.sp_promotion`: IBM Analytics [Site promotion](https://www.ibm.com/support/knowledgecenter/en/SSPG9M/Analytics/kc_welcome_analytics.html)
 * * `tp.ia.sp_link`: IBM Analytics [Site promotion link](https://www.ibm.com/support/knowledgecenter/en/SSPG9M/Analytics/kc_welcome_analytics.html)
 * * `tp.ia.re_version`: IBM Analytics [Real estate version](https://www.ibm.com/support/knowledgecenter/en/SSPG9M/Analytics/kc_welcome_analytics.html)
 * * `tp.ia.re_pagearea`: IBM Analytics [Real estate page area](https://www.ibm.com/support/knowledgecenter/en/SSPG9M/Analytics/kc_welcome_analytics.html)
 * * `tp.ia.re_link`: IBM Analytics [Real estate link](https://www.ibm.com/support/knowledgecenter/en/SSPG9M/Analytics/kc_welcome_analytics.html) *
 *
 * @class BOOMR.plugins.TPAnalytics
 */
/*eslint dot-notation:0*/
(function() {
	BOOMR = window.BOOMR || {};
	BOOMR.plugins = BOOMR.plugins || {};

	if (BOOMR.plugins.TPAnalytics) {
		return;
	}

	/**
	 * Warning logging
	 *
	 * @param {string} msg Message
	 */
	function warn(msg) {
		BOOMR.warn(msg, "TPAnalytics");
	}

	var impl = {
		complete: false,

		// collect client IDs, default to false
		// overridable by config
		clientids: false,

		// list of params we won't beacon
		// overridable by config
		dropParams: [],

		/**
		 * Google Analytics
		 * For Universal Analytics there is a function named "ga" which is used to retreive the clientid
		 * ref: https://developers.google.com/analytics/devguides/collection/analyticsjs/command-queue-reference
		 * By default the clientid is stored in a cookie named "_ga" for 2 years
		 * ref: https://developers.google.com/analytics/devguides/collection/analyticsjs/cookies-user-id
		 * For Classic GA, we'll parse the "__utma" cookie
		 *
		 * @return {Object} captured metrics
		 */
		googleAnalytics: function() {
			var data = {};
			var w = BOOMR.window;
			var i, param, value, cid, trackers;

			// list of query params that we want to capture
			// ref: https://support.google.com/analytics/answer/1033863
			var QUERY_PARAMS = ["utm_source", "utm_medium", "utm_term", "utm_content", "utm_campaign"];

			if (impl.clientids) {
				// check for google's global "ga" function then get the clientId
				if (typeof w.ga === "function") {
					try {
						w.ga(function(tracker) {
							// tracker may be undefined if using GTM or named trackers
							if (tracker) {
								data["clientid"] = tracker.get("clientId");
							}
						});
						if (!data["clientid"] && typeof w.ga.getAll === "function") {
							// we may have named trackers, the clientid should be the same for all of them
							trackers = w.ga.getAll();
							if (trackers && trackers.length > 0) {
								data["clientid"] = trackers[0].get("clientId");
							}
						}
					}
					catch (err) {
						// "ga" wasn't google analytics?
						warn("googleAnalytics: " + err);
					}
				}
				// if we still don't have the clientid then fallback to cookie parsing
				if (!data["clientid"]) {
					// cookie parsing for "Universal" GA
					// _ga cookie format : GA1.2.XXXXXXXXXX.YYYYYYYYYY
					// where XXXXXXXXXX.YYYYYYYYYY is the clientid
					cid = BOOMR.utils.getCookie("_ga");
					if (cid) {
						cid = cid.split(".");
						if (cid && cid.length === 4) {
							data["clientid"] = cid[2] + "." + cid[3];
						}
					}
					else {
						// cookie parsing for "Classic" GA
						// __utma #########.XXXXXXXXXX.YYYYYYYYYY.##########.##########.#
						// where XXXXXXXXXX.YYYYYYYYYY is the clientid
						cid = BOOMR.utils.getCookie("__utma");
						if (cid) {
							cid = cid.split(".");
							if (cid && cid.length === 6) {
								data["clientid"] = cid[1] + "." + cid[2];
							}
						}
					}
				}
			}

			// capture paramters from the url that are relevant to google analytics
			for (i = 0; i < QUERY_PARAMS.length; i++) {
				param = QUERY_PARAMS[i];
				value = BOOMR.utils.getQueryParamValue(param);
				if (value) {
					data[param] = value;
				}
			}

			return data;
		},

		/**
		 * Adobe Analytics
		 *
		 * AID: Analytics ID
		 * MID: Marketing ID
		 * Adobe's Marketing Cloud ID service uses a cookie named AMVC_#####@AdobeOrg,
		 * where ##### is the site owner's "client id". It stores the valud of MID and optionally AID
		 * If the site is not using Marketing Cloud, Analytics uses a legacy cookie named s_vi (AID)
		 * If the s_vi cookie is unable to be set due to 3rd party cookie restrictions,
		 * there is a fallback to a 1st party cookie named s_fid (AID).
		 *
		 * ref: https://marketing.adobe.com/resources/help/en_US/mcvid/mcvid_cookies.html
		 * ref: https://marketing.adobe.com/resources/help/en_US/mcvid/mcvid_idvars.html
		 * ref: https://marketing.adobe.com/resources/help/en_US/mcvid/mcvid_getmcvid.html
		 * ref: https://marketing.adobe.com/resources/help/en_US/mcvid/mcvid_getanalyticsvisitorid.html
		 *
		 * eVars and props aren't captured
		 *
		 * @return {Object} captured metrics
		 */
		adobeAnalytics: function() {
			var data = {};
			var aid, mid, amcv, visitor, m;
			var w = BOOMR.window;

			// regex that extracts the "organization id" from the AMCV_ cookie
			var AMCV_REGEX = /AMCV_([A-Z0-9]+)%40AdobeOrg/;

			// regex that extracts the id from the s_vi cookie (data between | and [)
			var SVI_REGEX = /\|([^\[]+)/;

			// check a few global vars to see if any Adobe products are installed
			// Adobe/Omniture's Data Tag Management global "_satellite" function
			// or Adobe/Omniture's Test&Target global "mboxCreate" function
			// or Adobe's Marketing Cloud ID Service's (AMCV) global "Visitor" function
			if (typeof w._satellite !== "undefined" || typeof w.mboxCreate === "function" || typeof w.Visitor === "function" || typeof w.s === "object") {
				if (impl.clientids) {
					// We'll try to fetch the "organization id" by using the global "s.visitor" object
					// "s" isn't reliably Adobe's SiteCatalyst object, the site owner might have renamed it
					if (typeof w.s === "object" &&
					    typeof w.s.visitor === "object" &&
					    typeof w.s.visitor.getAnalyticsVisitorID === "function" &&
					    typeof w.s.visitor.getMarketingCloudVisitorID === "function") {
						try {
							mid = w.s.visitor.getMarketingCloudVisitorID();
							if (mid) {
								data["mid"] = mid;
							}
							aid = w.s.visitor.getAnalyticsVisitorID();
							if (aid) {
								data["aid"] = w.s.visitor.getAnalyticsVisitorID();
							}
						}
						catch (err) {
							warn("adobeAnalytics: " + err);
						}
					}
					else {
						// Try extracting the "organization id" from the AMCV_ cookie instead
						// the result of Vistor.getInstance should be the same as if we did have "s.visitor"
						amcv = AMCV_REGEX.exec(w.document.cookie);
						if (amcv && typeof w.Visitor === "function" && typeof w.Visitor.getInstance === "function") {
							// we might have more than one AMCV_ cookie but we just take the first match for now
							try {
								visitor = w.Visitor.getInstance(amcv[1] + "@AdobeOrg");
								if (visitor && typeof visitor.getAnalyticsVisitorID === "function" && typeof visitor.getMarketingCloudVisitorID === "function") {
									mid = visitor.getMarketingCloudVisitorID();
									if (mid) {
										data["mid"] = mid;
									}
									aid = visitor.getAnalyticsVisitorID();
									if (aid) {
										data["aid"] = visitor.getAnalyticsVisitorID();
									}
								}
							}
							catch (err) {
								warn("adobeAnalytics: " + err);
							}
						}
						else {
							// AMCV doesn't seem to be installed
							// the legacy session id is in a cookie named s_vi if the publisher is using a cname to collect metrics
							// ie. third party cookie but on the same root domain name
							aid = BOOMR.utils.getCookie("s_vi");
							if (aid) {
								// s_vi will be in a format like this "[CS]v1|2B8147DA850785C4-6000010E2006DC28[CE]"
								// we need to extract the text between the pipe and the [CE]
								m = SVI_REGEX.exec(aid);
								if (m && m.length > 0) {
									aid = m[1];
								}
								else {
									aid = "";
								}
							}
							else {
								// fallback session id is a first party cookie named s_fid
								// eg. 6B280792FE0CFE56-162DA99B1988A2F8
								aid = BOOMR.utils.getCookie("s_fid");
							}
							if (aid) {
								data["aid"] = aid;
							}
						}
					}
				}

				if (typeof w.s === "object") {
					// get adobe campaign id
					// ref: https://marketing.adobe.com/resources/help/en_US/sc/implement/campaign.html
					if (typeof w.s.campaign === "string" && w.s.campaign) {
						data["campaign"] = w.s.campaign;
					}
					// get adobe purchase id
					// ref: https://marketing.adobe.com/resources/help/en_US/sc/implement/purchaseID.html
					if (typeof w.s.purchaseID === "string" && w.s.purchaseID) {
						data["purchaseid"] = w.s.purchaseID;
					}
				}
			}

			return data;
		},

		/**
		 * IBM Digital Analytics (CoreMetrics)
		 * IBM provides a global cmRetrieveUserID function to get the "Core ID" ("Visitor ID")
		 * The value is stored in a cookie named "CoreID6". Expiration: 15 years from date set.
		 * ref: https://www.ibm.com/support/knowledgecenter/SSPG9M/Implementation/AccessingIBMVisitorCookie.html
		 *
		 * off-site campaign information for "Marketing Management Center" (MMC), if available, is stored in a query parameter named "cm_mmc"
		 * ref: https://www.ibm.com/support/knowledgecenter/SSPG9M/Analytics/MarketingReports/cm_mmcparameter.html
		 *
		 * on-site "Site Promotions Analysis", if available, is stored in a query paramter named "cm_sp"
		 * ref: https://www.ibm.com/support/knowledgecenter/SSPG9M/Implementation/impl_sitepromo.html
		 *
		 * on-site "Real Estate Analysis", if available, is stored in a query parameter named "cm_re"
		 * ref: https://www.ibm.com/support/knowledgecenter/SSPG9M/Implementation/impl_realestate.html
		 *
		 * @return {Object} captured metrics
		 */
		ibmAnalytics: function() {
			var data = {};
			var w = BOOMR.window;
			var param, m, i, k, regex, fieldnames;

			// regexs to parse the query parameters into their fields
			var metrics = {
				"cm_mmc": [/([^&#]+?)-_-([^&#]+?)-_-([^&#]+?)-_-([^&#]+)/, ["mmc_vendor", "mmc_category", "mmc_placement", "mmc_item"]],
				"cm_sp": [/([^&#]+?)-_-([^&#]+?)-_-([^&#]+)/, ["sp_type", "sp_promotion", "sp_link"]],
				"cm_re": [/([^&#]+?)-_-([^&#]+?)-_-([^&#]+)/, ["re_version", "re_pagearea", "re_link"]]
			};

			if (impl.clientids && typeof w.cmRetrieveUserID === "function") {
				try {
					// in the current implementation of cmRetreiveUserID, the callback is called immediately (ie, not on a timer)
					w.cmRetrieveUserID(function(userid) {
						data["coreid"] = userid;
					});
				}
				catch (err) {
					// not coremetrics or not properly setup
					warn("ibmAnalytics: " + err);
				}
			}

			// capture analytics data from url query params
			for (k in metrics) {
				if (metrics.hasOwnProperty(k)) {
					param = BOOMR.utils.getQueryParamValue(k);
					if (param) {
						regex = metrics[k][0];
						fieldnames = metrics[k][1];
						m = regex.exec(param);
						if (m && m.length > fieldnames.length) {
							for (i = 0; i < fieldnames.length; i++) {
								if (m[i + 1]) {
									// value might be "null" or "na" but send it anyways
									data[fieldnames[i]] = decodeURIComponent(m[i + 1]);
								}
							}
						}
					}
				}
			}

			return data;
		},

		/**
		 * Executed on `page_ready` and `xhr_load`
		 */
		done: function(edata, ename) {
			var vendor, data, key, beaconParam;
			var vendors = {
				"ga": this.googleAnalytics,
				"aa": this.adobeAnalytics,
				"ia": this.ibmAnalytics
			};

			if (this.complete) {
				// we've already added data to the beacon
				return;
			}

			//
			// Don't add TPAnalytics to SPA Soft or XHR beacons --
			// Only add to Page Load (ename: load) and SPA Hard (ename: xhr
			// and initiator: spa_hard) beacons.
			//
			if (ename !== "load" && (!edata || edata.initiator !== "spa_hard")) {
				return;
			}

			for (vendor in vendors) {
				data = vendors[vendor]();
				for (var key in data) {
					var beaconParam = "tp." + vendor + "." + key;
					if (!BOOMR.utils.inArray(beaconParam, this.dropParams)) {
						BOOMR.addVar(beaconParam, data[key], true);
					}
				}
			}

			this.complete = true;

			BOOMR.sendBeacon();
		},

		/*
		 * Fired when the state changes from pre-render to visible
		 */
		prerenderToVisible: function() {
			// ensure we add our data to the beacon even if we had added it
			// during prerender (in case another beacon went out in between)
			this.complete = false;

			// add our data to the beacon
			this.done({}, "load");
		}
	};

	//
	// Exports
	//
	BOOMR.plugins.TPAnalytics = {
		/**
		 * Initializes the plugin.
		 *
		 * @param {object} config Configuration
		 * @param {boolean} config.TPAnalytics.clientids Whether or not to include
		 * client IDs.
		 * @param {string[]} config.TPAnalytics.dropParams Parameters to not include
		 * on the beacon.
		 *
		 * @returns {@link BOOMR.plugins.TPAnalytics} The TPAnalytics plugin for chaining
		 * @example
		 * BOOMR.init({
		 *   TPAnalytics: {
		 *     clientids: false
		 *   }
		 * });
		 * @memberof BOOMR.plugins.TPAnalytics
		 */
		init: function(config) {
			BOOMR.utils.pluginConfig(impl, config, "TPAnalytics", ["clientids", "dropParams"]);

			if (!impl.initialized) {
				if (!BOOMR.utils.isArray(impl.dropParams)) {
					impl.dropParams = [];
				}
				// we'll add data to the beacon on whichever happens first
				BOOMR.subscribe("page_ready", impl.done, "load", impl);
				BOOMR.subscribe("xhr_load", impl.done, "xhr", impl);
				BOOMR.subscribe("prerender_to_visible", impl.prerenderToVisible, "load", impl);
				impl.initialized = true;
			}

			return this;
		},

		/**
		 * This plugin is always complete (ready to send a beacon)
		 *
		 * @returns {boolean} `true`
		 * @memberof BOOMR.plugins.TPAnalytics
		 */
		is_complete: function() {
			return true;
		}
	};

}());
